package com.ebelter.btcomlib.models.bluetooth.products.scale;

import android.content.res.AssetManager;

import com.ebelter.btcomlib.AppConfigs;
import com.ebelter.btcomlib.CommonLib;
import com.ebelter.btcomlib.models.bluetooth.bean.SendMessage;
import com.ebelter.btcomlib.models.bluetooth.interfaces.IOtaUpdateCallback;
import com.ebelter.btcomlib.models.bluetooth.interfaces.IScaleUpdateCallback;
import com.ebelter.btcomlib.models.eventbus.CMDS;
import com.ebelter.btcomlib.models.eventbus.CommonEventBus;
import com.ebelter.btcomlib.utils.BytesUtils;

import com.ebelter.btcomlib.utils.ToastUtil;
import com.ebelter.btcomlib.utils.log.LogUtils;
import org.greenrobot.eventbus.EventBus;

import java.io.IOException;
import java.io.InputStream;
import java.util.ArrayList;
import java.util.List;

/**
 * 体脂秤的Ota升级工具类
 */

public class ScaleOtaUpdate {

    private static final String TAG = "ScaleOtaUpdate";

    private ScaleManager mScaleManager;//体脂管理器
    private ScaleBytesMakeFatory mScaleBytesMakeFatory;//制包工具类

    private static final int OTA_TYPE_SCALE = 2;
    private static final int OTA_TYPE_BLE = 1;
    //2是秤固件 1是蓝牙固件
    private int currentUpdateType=OTA_TYPE_SCALE;


    //private String ScaleSha256Code1;
    //private String ScaleSha256Code2;

    //private String BlueSha256Code1;
    //private String BlueSha256Code2;


    private byte SCALE_OTA_CheckCrc8 = 0;//秤的循环校验码
    private byte BLUE_OTA_CheckCrc8 = 0;//蓝牙的循环校验码

    //OTA数据包
    private List<byte[]> SCALE_OTA_ByteList;
    private List<byte[]> BLE_OTA_ByteList;


    StringBuilder desc=new StringBuilder();




    //这个回调接口是给用户显示的回调
    private IScaleUpdateCallback mIScaleUpdateCallback;

    //内部用的回调接口
    public IOtaUpdateCallback mIOtaUpdateCallback;


    private boolean isUpdateing_Flag;//是否正在升级标志位


    public void setUpdateing_Flag(boolean isUpdateing_Flag) {
        if (!isUpdateing_Flag){
            currentUpdateType=OTA_TYPE_SCALE;
        }
        this.isUpdateing_Flag=isUpdateing_Flag;

    }

    public ScaleOtaUpdate(ScaleManager scaleManager, ScaleBytesMakeFatory scaleBytesMakeFatory) {
        this.mScaleManager=scaleManager;
        this.mScaleBytesMakeFatory=scaleBytesMakeFatory;
        init();
    }

    private void init() {
        mIOtaUpdateCallback=new IOtaUpdateCallback() {
            @Override
            public void onGotScaleVersion(int bleVer, int scaleVer, int coefficientVer, int arithmeticVer) {
                //onGotScaleVersion:ble固件=65535 秤固件=4099 系数固件=65535 算法固件=65535 旧的

               // onGotScaleVersion:ble固件=65535 秤固件=34952 系数固件=65535 算法固件=65535 新
                LogUtils.i(TAG,"接收到版本信息---onGotScaleVersion:ble固件="+bleVer+" 秤固件="+scaleVer+" 系数固件="+coefficientVer+" 算法固件="+arithmeticVer);


            }

//            * 00：可以升级
//     01：不可升级（电量低）
            @Override
            public void onOtaUpgradeReady(int result) {
                LogUtils.i(TAG,"升级就绪回调接口接收到信息 result = "+result);

                if (result==1){//电量低不可升级
                    sendLog2ScaleTestActivity("电量低，不可以升级，升级退出",true);
                    isUpdateing_Flag = false;
                   // if (mIScaleUpdateCallback!=null) mIScaleUpdateCallback.finish(-1,"电量低，不可以升级，升级退出");

                }else if (result==0){//可以升级
                    startSendUpdateData();

                }else {
                    sendLog2ScaleTestActivity("特别注意：onOtaUpgradeReady-发现协议之外的命令字 result="+result,true);
                    if (mIScaleUpdateCallback!=null) mIScaleUpdateCallback.finish(-1,"onOtaUpgradeReady-发现协议之外的命令字 异常退出");
                }



            }

            @Override
            public void onReceiveSha256Pkg(int NO) {
//                LogUtils.i(TAG,"onReceiveSha256Pkg（）接收到回应 NO = "+NO);
//                if (NO==1){
//                    //准备下发第二包
//                    //sendSha256_2();
//                }else if (NO==2){
//                    startSendUpdateData();
//
//                }else {
//                    throw new RuntimeException("非法参数");
//                }

            }

            //升级包应答
            @Override
            public void onUpgradeResponse(int pkgNo, boolean result) {

                LogUtils.i(TAG,"接收到升级数据包应答 --result = "+result+"------pkgNo="+pkgNo);

                List<byte[]> dataList;

                desc.setLength(0);

                if (currentUpdateType==OTA_TYPE_SCALE){
                    dataList=SCALE_OTA_ByteList;
                    desc.append("正在升级秤固件");

                }else if (currentUpdateType==OTA_TYPE_BLE){
                    dataList=BLE_OTA_ByteList;
                    desc.append("正在升级蓝牙固件");

                }else {
                    throw new RuntimeException("非法参数");
                }

                desc.append("---total = "+dataList.size()+"--pkgNo="+pkgNo);

                sendLog2ScaleTestActivity(desc.toString(),true);



                LogUtils.i(TAG,desc.toString());



              //  sendUpdateData(dataList.get(pkgNo+1),pkgNo+1);



                if (result&&((pkgNo+1)<dataList.size())){
                    //说明下发成功 接着下发下一包
                    LogUtils.i(TAG,"成功接收---准备发下一包数据");
                    sendUpdateData(dataList.get(pkgNo+1),pkgNo+1);
                }else {
                    //说明下发失败 重新发送此包
                    LogUtils.i(TAG,"接收失败---准备重新发送此包数据");
                    sendUpdateData(dataList.get(pkgNo),pkgNo);
                }


            }

            /**
             * 升级结果
             * 当前升级类型：01（蓝牙）02（秤）
             升级结果:00：OK 01：超时ERR 02：CS出错 04：电量低
             */
            @Override
            public void onUpgradeResult(int result, int type) {
                isUpdateing_Flag = false;

                StringBuilder sb=new StringBuilder();
                String name;
                sb.append("接收到--");
                if (currentUpdateType==OTA_TYPE_SCALE){
                    name="秤固件";
                }else if (currentUpdateType==OTA_TYPE_BLE){
                    name="蓝牙固件";
                }else {
                    throw new RuntimeException("非法数据类型异常");
                }
                sb.append(name+"--升级结果 result:" + result+"   type = "+type);

                sendLog2ScaleTestActivity(sb.toString(),true);

                if (result==0){
                    sendLog2ScaleTestActivity(name + "升级成功",true);
                    if (currentUpdateType == OTA_TYPE_SCALE){
                        ToastUtil.show("秤固件--升级成功");
                        startUpdateBlue();
                    }else {
                        ToastUtil.show("蓝牙固件--升级成功");
                        currentUpdateType=OTA_TYPE_SCALE;
                        isUpdateing_Flag=false;
                      //  mScaleManager.getmServiceGatt().startSendHeart();
                    }
                }else {

                    String failureCause="";
                    if (result==1){

                        failureCause="--超时ERR";
                    }else if (result==2){
                        failureCause="--CS出错";
                    }else if (result==3){
                        failureCause="--电量低";
                    }
                    sendLog2ScaleTestActivity(name+failureCause+"升级失败",true);
                    currentUpdateType=OTA_TYPE_SCALE;
                    isUpdateing_Flag=false;
                    ToastUtil.show(name+failureCause+"升级失败");
                }






                //if (mIScaleUpdateCallback!=null) mIScaleUpdateCallback.updateResult(result,type);
            }
        };
    }

    //开始下发升级数据
    private void startSendUpdateData() {


        List<byte[]> data;

        if (currentUpdateType==OTA_TYPE_SCALE){
            data=SCALE_OTA_ByteList;
            LogUtils.i(TAG, "--开始下发--秤固件--升级数据包");
        }else if (currentUpdateType==OTA_TYPE_BLE){
            data=BLE_OTA_ByteList;
            LogUtils.i(TAG, "--开始下发--蓝牙固件--升级数据包");
        }else {
            throw new RuntimeException("非法参数异常");
        }

        sendUpdateData(data.get(0),0);




    }

    //下发更新数据
    private void sendUpdateData(byte[] bs, int pkgNo) {

        SendMessage sendMessage=mScaleBytesMakeFatory.getSendUpdateData(bs,pkgNo);

        LogUtils.i(TAG,"准备下发升级包pkgNo = " + pkgNo);
        LogUtils.i(TAG,"准备下发升级包内容是 = " + BytesUtils.bytes2HexStr(sendMessage.datas));

        mScaleManager.addSendMsg(sendMessage);

    }






    //用户显示用的回调接口
    public void setmScaleOtaUpdateListener(IScaleUpdateCallback mIScaleUpdateCallback) {
        this.mIScaleUpdateCallback = mIScaleUpdateCallback;
    }




    //开始更新
    public void startOtaUpdate(){

        if (isUpdateing_Flag){
            sendLog2ScaleTestActivity("-----固件升级已经在运行",true);
            ToastUtil.show("秤已经在升级中(如果发现log日志不对，请重新绑定设备重新点击升级按钮)");
            return;
        }

        startUpdateScale();
       // startUpdateBlue();

    }
    //开始升级蓝牙固件
    private void startUpdateBlue() {
        sendLog2ScaleTestActivity("-----开始--蓝牙固件--升级----",true);
        isUpdateing_Flag=true;
        currentUpdateType=OTA_TYPE_BLE;

        setOtaBlueBytes(AppConfigs.UPDATE_OTA_BLUETOOTH);//初始胡秤的升级数据
       // setOtaBlueBytes("BLE_OTA_lnv_111.bin");//初始胡秤的升级数据


        LogUtils.i(TAG,"初始化完蓝牙固件以后---BLE_OTA_ByteList.size()="+BLE_OTA_ByteList.size()+"---BLUE_OTA_CheckCrc8 = "+BLUE_OTA_CheckCrc8);


        sendLog2ScaleTestActivity("下发--蓝牙固件--升级请求。。。",true);

        mScaleManager.addSendMsg(mScaleBytesMakeFatory.getOTAUpdateRequest(OTA_TYPE_BLE,BLE_OTA_ByteList.size(),BLUE_OTA_CheckCrc8));
    }


    //开始升级秤固件
    private void startUpdateScale() {
        sendLog2ScaleTestActivity("-----开始--秤固件--升级----",true);
        isUpdateing_Flag=true;
        currentUpdateType=OTA_TYPE_SCALE;

        setOtaScaleBytes(AppConfigs.UPDATE_OTA_SCALE);//初始胡秤的升级数据

      //  setOtaScaleBytes("OTA_S-F231_lianxiang_LED_0xBBDE_34M97_20180601.BIN");//初始胡秤的升级数据

        LogUtils.i(TAG,"初始化完秤固件以后---SCALE_OTA_ByteList.size()="+SCALE_OTA_ByteList.size()+"---SCALE_OTA_CheckCrc8 = "+SCALE_OTA_CheckCrc8);


        sendLog2ScaleTestActivity("下发--秤固件--升级请求。。。",true);

        mScaleManager.addSendMsg(mScaleBytesMakeFatory.getOTAUpdateRequest(OTA_TYPE_SCALE,SCALE_OTA_ByteList.size(),SCALE_OTA_CheckCrc8));



    }

    //开始秤的数据初始化
    private void setOtaScaleBytes(String name) {

        SCALE_OTA_ByteList = new ArrayList<>();
        SCALE_OTA_CheckCrc8 = 0;

        AssetManager assetManager = CommonLib.APPContext.getResources().getAssets();
        InputStream input = null;
        try {
            input = assetManager.open(name);
            byte[] tempBytes = new byte[16];
            int readByte;
            while ((readByte = input.read(tempBytes)) != -1) {
                byte[] bs = tempBytes.clone();
                //每一包接收之后都进行处理

                SCALE_OTA_CheckCrc8 = getCrc8Check(bs, SCALE_OTA_CheckCrc8);
                SCALE_OTA_ByteList.add(bs);
            }

        } catch (IOException e) {
            e.printStackTrace();
        } finally {
            if (input != null) {
                try {
                    input.close();
                } catch (IOException e) {
                    e.printStackTrace();
                }
            }
        }

    }

    //开始秤的数据初始化
    private void setOtaBlueBytes(String name) {

        BLE_OTA_ByteList = new ArrayList<>();
        BLUE_OTA_CheckCrc8=0;

        AssetManager assetManager = CommonLib.APPContext.getResources().getAssets();
        InputStream input = null;
        try {
            input = assetManager.open(name);
            byte[] tempBytes = new byte[16];
            int readByte;
            while ((readByte = input.read(tempBytes)) != -1) {
                byte[] bs = tempBytes.clone();
                //每一包接收之后都进行处理

                BLUE_OTA_CheckCrc8 = getCrc8Check(bs, BLUE_OTA_CheckCrc8);
                BLE_OTA_ByteList.add(bs);
            }

        } catch (IOException e) {
            e.printStackTrace();
        } finally {
            if (input != null) {
                try {
                    input.close();
                } catch (IOException e) {
                    e.printStackTrace();
                }
            }
        }

    }












    /**
     * CRC8校验
     */
    private byte getCrc8Check(byte[] bytes, byte result) {
        int size = bytes.length;
        for (byte aByte : bytes) {
            result ^= aByte;
            for (int j = 0; j < 8; j++) {
                if ((result & 0x80) > 0) {
                    result <<= 1;
                    result = (byte) (result ^ 7);
                } else {
                    result <<= 1;
                }
            }
        }
        return result;
    }


//    //计算某个字节数组的循环校验码
//    private byte getCrc8Check(byte[] bytes) {
//        int crcCode = 0;
//        for (byte aByte : bytes) {
//            crcCode ^= aByte;
//        }
//        return (byte) crcCode;
//    }

    private void sendLog2ScaleTestActivity(String log,boolean isLog){
        CommonEventBus event=new CommonEventBus(TAG, "ScaleTestActivity", CMDS.LOG_ScaleTestActivity,log);
        EventBus.getDefault().post(event);
        if (isLog){
            LogUtils.i(TAG,log);
        }
    }
}
